/*
 * File: Message.java Author: Robert Bittle <guywithnose@gmail.com>
 */
package faceBook;

import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.logging.Logger;

import org.hsqldb.types.Types;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONString;

import data.JavaCurl;

import foxtrotbravo.DataConnection;
import foxtrotbravo.DataObject;

/**
 * The Class Message.
 */
public class Message implements DataObject, JSONString
{

  /** The Constant log. */
  private static final Logger log = Logger.getLogger(Message.class
      .getName());

  /** The ID. */
  private long ID;

  /** The user. */
  private User user;

  /** The message. */
  private String message;

  /** The link. */
  private String link;

  /** The send date. */
  private Date sendDate;

  /** The type. */
  private String type;

  /** The type. */
  private long holiday;

  /** The comment on. */
  private String commentOn;
  
  /** The is default. */
  private boolean isDefault;

  /**
   * The Class MessageFriend.
   */
  public static class MessageFriend
  {

    /** The friend. */
    public User friend;

    /** The confirmation. */
    public String confirmation;

    /**
     * Instantiates a new message friend.
     * 
     * @param Friend
     *          the friend
     */
    public MessageFriend(User Friend)
    {
      friend = Friend;
    }

  }

  /** The friend list. */
  private ArrayList<MessageFriend> friendList = new ArrayList<MessageFriend>();

  /**
   * Instantiates a new message.
   */
  public Message()
  {
  }

  /**
   * Instantiates a new message.
   * 
   * @param id
   *          the id
   */
  public Message(long id)
  {
    ID = id;
    load();
  }

  /**
   * Gets the iD.
   * 
   * @return the iD
   */
  public long getID()
  {
    return ID;
  }

  /**
   * Sets the iD.
   * 
   * @param iD
   *          the new iD
   */
  public void setID(long iD)
  {
    ID = iD;
  }

  /**
   * Gets the user.
   * 
   * @return the user
   */
  public User getUser()
  {
    return user;
  }

  /**
   * Sets the user.
   * 
   * @param USER
   *          the new user
   */
  public void setUser(User USER)
  {
    user = USER;
  }

  /**
   * Gets the message.
   * 
   * @return the message
   */
  public String getMessage()
  {
    return message;
  }

  /**
   * Sets the message.
   * 
   * @param Message
   *          the new message
   */
  public void setMessage(String Message)
  {
    message = Message;
  }

  /**
   * Gets the link.
   * 
   * @return the link
   */
  public String getLink()
  {
    return link;
  }

  /**
   * Sets the link.
   * 
   * @param Link
   *          the new link
   */
  public void setLink(String Link)
  {
    link = Link;
  }

  /**
   * Gets the send date.
   * 
   * @return the send date
   */
  public Date getSendDate()
  {
    return sendDate;
  }

  /**
   * Sets the send date.
   * 
   * @param SendDate
   *          the new send date
   */
  public void setSendDate(Date SendDate)
  {
    sendDate = SendDate;
  }

  /**
   * Sets the send date.
   * 
   * @param SendDate
   *          the new send date
   */
  public void setSendDate(long SendDate)
  {
    sendDate = new Date(SendDate);
  }

  /**
   * Get Confirmations.
   * 
   * @return the confirmations
   */
  public String getConfirmations()
  {
    String confirmations = "";
    for (MessageFriend messageFriend : friendList)
    {
      if (messageFriend.confirmation != null)
        confirmations += messageFriend.confirmation + ",";
    }
    return confirmations.replaceAll(",$", "");
  }

  /**
   * Sets the confirmation.
   * 
   * @param confirmation
   *          the new confirmation
   * @param friend
   *          the friend
   */
  public void setConfirmation(String confirmation, User friend)
  {
    for (MessageFriend messageFriend : friendList)
    {
      if (messageFriend.friend.getID() == friend.getID())
        messageFriend.confirmation = confirmation;
    }
  }

  /**
   * Get Type.
   * 
   * @return the type
   */
  public String getType()
  {
    return type;
  }

  /**
   * Sets the type.
   * 
   * @param Type
   *          the new type
   */
  public void setType(String Type)
  {
    type = Type;
  }

  /**
   * Get Holiday.
   * 
   * @return the holiday
   */
  public long getHoliday()
  {
    return holiday;
  }

  /**
   * Sets the holiday.
   * 
   * @param Holiday
   *          the new holiday
   */
  public void setHoliday(long Holiday)
  {
    holiday = Holiday;
  }

  /**
   * Get Comment on.
   *
   * @return the comment on
   */
  public String getCommentOn()
  {
    return commentOn;
  }

  /**
   * Checks if is default.
   *
   * @return true, if is default
   */
  public boolean isDefault()
  {
    return isDefault;
  }

  /**
   * Sets the default.
   *
   * @param IsDefault the new default
   */
  public void setDefault(boolean IsDefault)
  {
    isDefault = IsDefault;
  }

  /**
   * Sets the comment on.
   *
   * @param CommentOn the new comment on
   */
  public void setCommentOn(String CommentOn)
  {
    commentOn = CommentOn;
  }

  /*
   * (non-Javadoc)
   * 
   * @see org.json.JSONString#toJSONString()
   */
  @Override
  public String toJSONString()
  {
    return toJSONObject().toString();
  }

  /**
   * To json object.
   * 
   * @return the jSON object
   */
  public JSONObject toJSONObject()
  {
    JSONObject JO = new JSONObject();
    try
    {
      JO.put("id", ID);
      JO.put("user", new JSONObject(user.toJSONString()));
      JSONArray jsonFriendList = new JSONArray();
      for (MessageFriend thisMessagefriend : friendList)
      {
        JSONObject messageFriend = new JSONObject();
        messageFriend.put("friend", thisMessagefriend.friend.toJSONObject());
        messageFriend.put("confirmation", thisMessagefriend.confirmation);
        jsonFriendList.put(messageFriend);
      }
      JO.put("friendList", jsonFriendList);
      JO.put("message", message);
      JO.put("link", link);
      JO.put("sendDate", sendDate);
      JO.put("type", type);
      JO.put("holiday", holiday);
      JO.put("commentOn", commentOn);
      JO.put("isDefault", isDefault);
      JO.put("isSent", getConfirmations() != "");
    } catch (JSONException e)
    {
      // Do Nothing
    }
    return JO;
  }

  /*
   * (non-Javadoc)
   * 
   * @see java.lang.Object#toString()
   */
  @Override
  public String toString()
  {
    return toJSONString();
  }

  /*
   * (non-Javadoc)
   * 
   * @see foxtrotbravo.DataObject#save()
   */
  @Override
  public boolean save()
  {
    try
    {
      if (ID != 0)
      {
        return update();
      }
      return insert();
    } catch (SQLException e)
    {
      e.printStackTrace();
    }
    return false;
  }

  /*
   * (non-Javadoc)
   * 
   * @see foxtrotbravo.DataObject#load()
   */
  @Override
  public boolean load()
  {
    try
    {
      if (DataConnection.connect())
      {
        String statement = "select user, message, link, sendDate, type, holiday, commentOn, isDefault from message where id = ?";
        PreparedStatement stmt = DataConnection.getConnection()
            .prepareStatement(statement);
        stmt.setLong(1, ID);
        ResultSet results = stmt.executeQuery();
        if (results.next())
        {
          user = new User(results.getLong("user"));
          message = results.getString("message");
          link = results.getString("link");
          sendDate = results.getDate("sendDate");
          type = results.getString("type");
          holiday = results.getLong("holiday");
          commentOn = results.getString("commentOn");
          isDefault = results.getBoolean("isDefault");
          loadFriendList();
          return true;
        }
      }
    } catch (SQLException e)
    {
      e.printStackTrace();
    }
    return false;
  }

  /*
   * (non-Javadoc)
   * 
   * @see foxtrotbravo.DataObject#delete()
   */
  @Override
  public boolean delete()
  {
    try
    {
      if (DataConnection.connect())
      {
        String statement = "delete from message where id = ?";
        PreparedStatement stmt = DataConnection.getConnection()
            .prepareStatement(statement);
        stmt.setLong(1, ID);
        int success = 2;
        success = stmt.executeUpdate();
        return success == 1;
      }
    } catch (SQLException e)
    {
      e.printStackTrace();
    }
    return true;
  }

  /**
   * Update.
   * 
   * @return true, if successful
   * @throws SQLException
   *           the SQL exception
   */
  private boolean update() throws SQLException
  {
    if (DataConnection.connect())
    {
      String statement = "update message set user = ?, message = ?, link = ?, sendDate = ?, type = ?, holiday = ?, commentOn = ?, isDefault = ? where id = ?";
      PreparedStatement stmt = DataConnection.getConnection().prepareStatement(
          statement);
      if (user != null)
        stmt.setLong(1, user.getID());
      else
        stmt.setNull(1, Types.BIGINT);
      stmt.setString(2, message);
      stmt.setString(3, link);
      stmt.setDate(4, sendDate);
      stmt.setString(5, type);
      stmt.setLong(6, holiday);
      stmt.setString(7, commentOn);
      stmt.setBoolean(8, isDefault);
      stmt.setLong(9, ID);
      int success = 2;
      success = stmt.executeUpdate();

      saveFriendList();

      return success == 1;
    }
    return false;
  }

  /**
   * Insert.
   * 
   * @return true, if successful
   * @throws SQLException
   *           the sQL exception
   */
  private boolean insert() throws SQLException
  {
    if (DataConnection.connect())
    {
      String statement = "INSERT INTO message (user, message, link, sendDate, type, holiday, commentOn, isDefault) VALUES ( ?, ?, ?, ?, ?, ?, ?, ? )";
      PreparedStatement stmt = DataConnection.getConnection().prepareStatement(
          statement, Statement.RETURN_GENERATED_KEYS);
      if (user != null)
        stmt.setLong(1, user.getID());
      else
        stmt.setNull(1, Types.BIGINT);
      stmt.setString(2, message);
      stmt.setString(3, link);
      stmt.setDate(4, sendDate);
      stmt.setString(5, type);
      stmt.setLong(6, holiday);
      stmt.setString(7, commentOn);
      stmt.setBoolean(8, isDefault);
      int success = 2;
      success = stmt.executeUpdate();
      ResultSet key = stmt.getGeneratedKeys();
      if (key.next())
      {
        ID = key.getLong(1);
      }

      saveFriendList();

      return success == 1;
    }
    return false;
  }

  /**
   * Removes the friend list from db.
   * 
   * @throws SQLException
   *           the sQL exception
   */
  private void saveFriendList() throws SQLException
  {
    String statement = "delete from message_friend where message = ?";
    PreparedStatement stmt = DataConnection.getConnection().prepareStatement(
        statement);
    stmt.setLong(1, ID);
    stmt.executeUpdate();

    for (MessageFriend messageFriend : friendList)
    {
      statement = "insert into message_friend (message, friend, confirmation) values ( ?, ?, ? )";
      stmt = DataConnection.getConnection().prepareStatement(statement);
      stmt.setLong(1, ID);
      stmt.setLong(2, messageFriend.friend.getID());
      stmt.setString(3, messageFriend.confirmation);
      stmt.executeUpdate();
    }
  }

  /**
   * Post message.
   */
  public void postMessage()
  {
    log.info("Attempting to send message " + getID());
    if (user.hasPostPermissions())
    {
      String accessToken = user.getAccessToken();
      for (MessageFriend messageFriend : friendList)
      {
        if (messageFriend.confirmation == null)
        {
          long friendID = messageFriend.friend.getID();
          HashMap<String, String> options = new HashMap<String, String>();

          options.put("message", message);
          if (link == null)
            options.put("link", "");
          else
            options.put("link", link);

          String url = "https://graph.facebook.com/" + friendID
              + "/feed?access_token=" + accessToken;
          String response = JavaCurl.getUrl(url, "POST", options);

          try
          {
            JSONObject jo = new JSONObject(response);
            messageFriend.confirmation = jo.getString("id");
            save();
            log.info("Sent message " + getID() + " to friend " + friendID);
          } catch (JSONException e)
          {
            e.printStackTrace();
            System.err.println(response);
          }
        }
      }
    }
  }

  /**
   * Post comment.
   */
  public void postComment()
  {
    log.info("Attempting to send comment " + getID());
    if (user.hasPostPermissions())
    {
      String accessToken = user.getAccessToken();
      for (MessageFriend messageFriend : friendList)
      {
        if (messageFriend.confirmation == null)
        {
          long friendID = messageFriend.friend.getID();
          HashMap<String, String> parameters = new HashMap<String, String>();

          parameters.put("message", message);

          String url = "https://graph.facebook.com/" + getCommentOn()
              + "/comments?access_token=" + accessToken;
          String response = JavaCurl.getUrl(url, "POST", parameters);

          try
          {
            JSONObject jo = new JSONObject(response);
            messageFriend.confirmation = jo.getString("id");
            save();
            log.info("Sent comment " + getID() + " on message " + " to friend " + friendID);
          } catch (JSONException e)
          {
            e.printStackTrace();
            System.err.println(response);
          }
        }
      }
    }
  }

  /**
   * Get All message for day.
   * 
   * @param day
   *          the day
   * @return the all message for day
   */
  public static ArrayList<Message> getAllMessageForDay(GregorianCalendar day)
  {

    ArrayList<Message> messages = new ArrayList<Message>();
    try
    {
      if (DataConnection.connect())
      {
        String month = String.valueOf(day.get(Calendar.MONTH) + 1);
        String date = String.valueOf(day.get(Calendar.DATE));
        String year = String.valueOf(day.get(Calendar.YEAR));
        String statement = "select id from message where sendDate < DATE('"
            + year + "-" + month + "-" + date + "')+1 and sendDate > DATE('"
            + year + "-" + month + "-" + date + "')-1";
        PreparedStatement stmt = DataConnection.getConnection()
            .prepareStatement(statement);
        ResultSet results = stmt.executeQuery();
        while (results.next())
        {
          messages.add(new Message(results.getLong("id")));
        }
      }
    } catch (SQLException e)
    {
      e.printStackTrace();
    }
    return messages;
  }

  /**
   * Get All messages for user.
   * 
   * @param user
   *          the user
   * @return the all messages for user
   */
  public static ArrayList<Message> getAllMessagesForUser(User user)
  {

    ArrayList<Message> messages = new ArrayList<Message>();
    try
    {
      if (DataConnection.connect())
      {
        String statement = "select id from message where user = ?";
        PreparedStatement stmt = DataConnection.getConnection()
            .prepareStatement(statement);
        stmt.setLong(1, user.getID());
        ResultSet results = stmt.executeQuery();
        while (results.next())
        {
          messages.add(new Message(results.getLong("id")));
        }
      }
    } catch (SQLException e)
    {
      e.printStackTrace();
    }
    return messages;
  }
  
  /**
   * Get User custom message count.
   *
   * @param user the user
   * @return the user custom message count
   */
  public static int getUserCustomMessageCount(User user)
  {
    try
    {
      if (DataConnection.connect())
      {
        String statement = "select count(id) as count from message where user = ? and isDefault = false";
        PreparedStatement stmt = DataConnection.getConnection()
            .prepareStatement(statement);
        stmt.setLong(1, user.getID());
        ResultSet results = stmt.executeQuery();
        if (results.next())
        {
          return results.getInt("count");
        }
      }
    } catch (SQLException e)
    {
      e.printStackTrace();
    }
    return 0;
  }
  
  /**
   * Gets the friends.
   */
  private void loadFriendList()
  {
    try
    {
      if (DataConnection.connect())
      {
        String statement = "select friend, confirmation from message_friend where message = ?";
        PreparedStatement stmt = DataConnection.getConnection()
            .prepareStatement(statement);
        stmt.setLong(1, ID);
        ResultSet results = stmt.executeQuery();
        friendList = new ArrayList<MessageFriend>();
        while (results.next())
        {
          User friend = new User(results.getLong("friend"));
          MessageFriend messageFriend = new MessageFriend(friend);
          messageFriend.confirmation = results.getString("confirmation");
          friendList.add(messageFriend);
        }
      }
    } catch (SQLException e)
    {
      e.printStackTrace();
    }
  }

  /**
   * Adds the friend.
   * 
   * @param newUser
   *          the new user
   */
  public void addFriend(User newUser)
  {
    friendList.add(new MessageFriend(newUser));
  }

  /**
   * Sets the friend list.
   * 
   * @param FriendList
   *          the new friend list
   */
  public void setFriendList(ArrayList<MessageFriend> FriendList)
  {
    friendList = FriendList;
  }

  /**
   * Get Friend list.
   * 
   * @return the friend list
   */
  public ArrayList<MessageFriend> getFriendList()
  {
    return friendList;
  }

  /**
   * Post has comment.
   *
   * @param postId the post id
   * @return true, if successful
   */
  public static boolean postHasComment(String postId)
  {
    try
    {
      if (DataConnection.connect())
      {
        String statement = "select 1 from message where commentOn = ?";
        PreparedStatement stmt = DataConnection.getConnection()
            .prepareStatement(statement);
        stmt.setString(1, postId);
        ResultSet results = stmt.executeQuery();
        if (results.next())
        {
          return true;
        }
      }
    } catch (SQLException e)
    {
      e.printStackTrace();
    }
    return false;
  }

}
